﻿using Microsoft.Extensions.DependencyModel;
using System;
using System.IO;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.Loader;

namespace Lynn.Infastructure.Utils
{
    public static class AssemblyHelper
    {
        static readonly List<CompilationLibrary> compilationLibraries;
        static AssemblyHelper()
        {
            compilationLibraries = DependencyContext.Default.CompileLibraries.Where(c => !c.Serviceable && c.Type == "project").ToList();
        }
        /// <summary>
        /// 动态创建实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assemblyName"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static T CreateInstance<T>(string assemblyName, string typeName) where T : class
        {
            var ass = GetAssembly(assemblyName);
            Type type = ass.GetType(assemblyName + "." + typeName);
            //创建
            T t = (T)Activator.CreateInstance(type);
            return t;
        }
        /// <summary>
        /// 程序集名称 不带DLL
        /// </summary>
        /// <param name="assemblyName">程序集名称 不带DLL</param>
        /// <param name="useByte">使用byte[] 参数加载程序集，这样不占用程序集文件。会有莫名其妙的问题 目前已知有个Linq问题 后续研究AssemblyLoadContext</param>
        /// <returns></returns>
        public static Assembly GetAssembly(string assemblyName)
        {
            var path = AppDomain.CurrentDomain.BaseDirectory;
            var name = "";
            if (assemblyName.EndsWith(".dll"))
            {
                name = assemblyName;
            }
            else
            {
                name = $"{assemblyName}.dll";
            }
            return AssemblyLoadContext.CurrentContextualReflectionContext.LoadFromAssemblyPath(Path.Combine(path, name));

        }
        /// <summary>
        /// 获取TypeInfo
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static List<TypeInfo> FindTypeInfos(Func<TypeInfo, bool> where, string assemblyName = null)
        {
            var list = new List<Assembly>();
            if (!string.IsNullOrWhiteSpace(assemblyName))
            {
                list.Add(GetAssembly(assemblyName));
            }
            else
            {
                var libs = compilationLibraries;
                //将程序集加载,并存放进list
                libs.ForEach((x) => { list.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(x.Name))); });
            }
            var types = new List<TypeInfo>();
            foreach (var assemb in list)
            {
                types = types.Union(assemb.DefinedTypes.Where(where).ToList()).ToList();
            }
            return types;
        }
    }
}
